from PyQt5 import QtWidgets, QtCore
from PyQt5.QtGui import QColor, QPixmap
from PyQt5.QtWidgets import QGraphicsScene, QGraphicsRectItem, QGraphicsEllipseItem, QGraphicsPixmapItem
from PyQt5.QtCore import Qt, QRectF, QObject
import sys
import os
import traceback
import configparser
import ast

def excepthook(exc_type, exc_value, exc_tb):
    traceback.print_exception(exc_type, exc_value, exc_tb)
    sys.exit(1)

sys.excepthook = excepthook

class GraphicsViewDrawer(QObject):
    def __init__(self, graphics_view):
        super().__init__()
        self.graphics_view = graphics_view
        self.scene = QGraphicsScene()
        self.graphics_view.setScene(self.scene)
        self.draw_mode = ""
        self.current_item = None
        self.last_item = None
        self.start_point = None
        self.pixmap_item = None
        
        # 安装事件过滤器处理窗口缩放
        self.graphics_view.viewport().installEventFilter(self)
        
        # 连接鼠标事件
        self.graphics_view.mousePressEvent = self.mouse_press_event
        self.graphics_view.mouseMoveEvent = self.mouse_move_event
        self.graphics_view.mouseReleaseEvent = self.mouse_release_event

    def eventFilter(self, source, event):
        if event.type() == QtCore.QEvent.Resize:
            self.adjust_image()
        return super().eventFilter(source, event)

    def adjust_image(self):
        if self.pixmap_item:
            self.graphics_view.fitInView(self.pixmap_item, Qt.KeepAspectRatio)

    def set_draw_mode(self, mode):
        self.draw_mode = mode

    def clear_scene(self):
        for item in self.scene.items():
            self.scene.removeItem(item)
        self.scene.update()
        self.draw_mode = ""
        self.pixmap_item = None

    def load_image(self, image_path):
        pixmap = QPixmap(image_path)
        if pixmap.isNull():
            print(f"无法加载图片: {image_path}")
            return
        
        self.pixmap_item = QGraphicsPixmapItem(pixmap)
        self.scene.addItem(self.pixmap_item)
        self.adjust_image()
        self.load_roi()  # 加载图片后自动加载ROI

    def load_roi(self):
        if not self.pixmap_item:
            return

        # 清理旧ROI
        if self.last_item:
            self.scene.removeItem(self.last_item)
            self.last_item = None
            
        config = configparser.ConfigParser()
        if not os.path.exists("seting.ini"):
            return
            
        config.read("seting.ini", encoding="utf-8")
        if not config.has_section("ROI0"):
            return
            
        bbox_str = config.get("ROI0", "bbox", fallback="None")
        bbox_type = config.get("ROI0", "type", fallback="None")
        
        if bbox_str != "None":
            try:
                bbox_list = ast.literal_eval(bbox_str)
                x, y, w, h = map(float, bbox_list)
                local_rect = QRectF(x, y, w, h)
                scene_rect = self.pixmap_item.mapRectToScene(local_rect)
                
                if bbox_type == "QGraphicsRectItem":
                    self.last_item = QGraphicsRectItem(scene_rect)
                elif bbox_type == "QGraphicsEllipseItem":
                    self.last_item = QGraphicsEllipseItem(scene_rect)
                
                if self.last_item:
                    self.last_item.setPen(QColor(255, 0, 0))
                    self.last_item.setZValue(1)
                    self.scene.addItem(self.last_item)
            except Exception as e:
                print(f"加载ROI时出错: {e}")

    def mouse_press_event(self, event):
        if self.draw_mode and self.pixmap_item:
            self.start_point = self.graphics_view.mapToScene(event.pos())
            if self.draw_mode == "Rect":
                self.current_item = QGraphicsRectItem(0, 0, 0, 0)
            elif self.draw_mode == "Ellipse":
                self.current_item = QGraphicsEllipseItem(0, 0, 0, 0)
            
            if self.current_item:
                self.current_item.setPos(self.start_point)
                self.current_item.setPen(QColor(255, 0, 0))
                self.current_item.setZValue(1)
                self.scene.addItem(self.current_item)
                if self.last_item:
                    self.scene.removeItem(self.last_item)

    def mouse_move_event(self, event):
        if self.draw_mode and self.current_item and self.pixmap_item:
            end_point = self.graphics_view.mapToScene(event.pos())
            width = end_point.x() - self.start_point.x()
            height = end_point.y() - self.start_point.y()
            
            if self.draw_mode == "Rect":
                self.current_item.setRect(0, 0, width, height)
            elif self.draw_mode == "Ellipse":
                self.current_item.setRect(0, 0, width, height)

    def mouse_release_event(self, event):
        if self.draw_mode and self.current_item and self.pixmap_item:
            self.last_item = self.current_item
            scene_rect = self.last_item.sceneBoundingRect()
            local_rect = self.pixmap_item.mapRectFromScene(scene_rect)
            
            config = configparser.ConfigParser()
            config.read("seting.ini", encoding="utf-8")
            if not config.has_section("ROI0"):
                config.add_section("ROI0")
                
            config.set('ROI0', 'bbox', str([local_rect.x(), local_rect.y(), 
                                          local_rect.width(), local_rect.height()]))
            config.set('ROI0', 'type', type(self.last_item).__name__)
            
            try:
                with open('seting.ini', 'w') as configfile:
                    config.write(configfile)
            except Exception as e:
                print(f"保存ROI时出错: {e}")

if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    main_window = QtWidgets.QMainWindow()
    main_window.setWindowTitle("GraphicsViewDrawer 测试")
    main_window.resize(800, 600)
    
    central_widget = QtWidgets.QWidget()
    main_window.setCentralWidget(central_widget)
    layout = QtWidgets.QVBoxLayout(central_widget)
    
    graphics_view = QtWidgets.QGraphicsView()
    layout.addWidget(graphics_view)
    
    button_layout = QtWidgets.QHBoxLayout()
    btn_rect = QtWidgets.QPushButton("绘制矩形")
    btn_ellipse = QtWidgets.QPushButton("绘制椭圆")
    btn_clear = QtWidgets.QPushButton("清除画布")
    btn_load = QtWidgets.QPushButton("加载图片")
    
    button_layout.addWidget(btn_rect)
    button_layout.addWidget(btn_ellipse)
    button_layout.addWidget(btn_clear)
    button_layout.addWidget(btn_load)
    layout.addLayout(button_layout)
    
    drawer = GraphicsViewDrawer(graphics_view)
    
    btn_rect.clicked.connect(lambda: drawer.set_draw_mode("Rect"))
    btn_ellipse.clicked.connect(lambda: drawer.set_draw_mode("Ellipse"))
    btn_clear.clicked.connect(drawer.clear_scene)
    btn_load.clicked.connect(lambda: drawer.load_image("./snap/lout_00000.jpg"))
    
    main_window.show()
    sys.exit(app.exec_())
